package com.robam.cloud.log.aop;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.robam.cloud.common.bean.common.Constant;
import com.robam.cloud.common.bean.log.entity.LogInfo;
import com.robam.cloud.common.util.RequestUtil;
import com.robam.cloud.log.annotation.OperationLogRecord;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Date;

@Component
@Aspect
@Slf4j
public class AnnotationLogRecordAspect {

    private ThreadLocal<LogInfo> logInfoLocal = new ThreadLocal<LogInfo>() {
        protected LogInfo initialValue() {
            return new LogInfo();
        }

        ;
    };

    @Autowired
    private ObjectMapper objectMapper;

    public AnnotationLogRecordAspect() {
    }


    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) || @annotation(org.springframework.web.bind.annotation.PostMapping) || @annotation(org.springframework.web.bind.annotation.GetMapping) || @annotation(org.springframework.web.bind.annotation.DeleteMapping) || @annotation(org.springframework.web.bind.annotation.DeleteMapping) || @annotation(org.springframework.web.bind.annotation.PutMapping)")
    public void oprationLog() {
    }


    @Around("oprationLog()&& @annotation(operationLogRecord)")
    public Object around(ProceedingJoinPoint point, OperationLogRecord operationLogRecord) throws Throwable {
        log.debug("<=====================================================");
        log.debug("日志切片start...around");
        this.setLogInfo(point, operationLogRecord);
        Object object = point.proceed();
        log.debug("日志切片end...around");
        log.debug("=====================================================>");
        return object;
    }

    @Before("oprationLog() && @annotation(operationLogRecord)")
    public void beforeOprationLog(JoinPoint point, OperationLogRecord operationLogRecord) {
        log.debug("日志切片Before");
    }

    @After("oprationLog() && @annotation(operationLogRecord)")
    public void afterOprationLog(JoinPoint point, OperationLogRecord operationLogRecord) {
        log.debug("logInfoLocal:{}", this.logInfoLocal.get());
        this.logInfoLocal.remove();
    }


    @AfterReturning(pointcut = "oprationLog()&& @annotation(operationLogRecord)", returning = "result")
    public Object afterReturning(JoinPoint joinPoint, OperationLogRecord operationLogRecord, Object result) {
        try {
            ((LogInfo) this.logInfoLocal.get()).setReturnResult(this.objectMapper.writeValueAsString(result).length() > 2000 ? this.objectMapper.writeValueAsString(result).substring(0, 1800) : this.objectMapper.writeValueAsString(result));
            ((LogInfo) this.logInfoLocal.get()).setExceptionInfo(null);
        } catch (Exception var4) {
            log.debug("日志切片AfterReturning方法=>返回结果格式化json异常： " + var4.getMessage());
        }
        return result;
    }


    @AfterThrowing(pointcut = "execution(public * com.robam..*.controller.*.*(..))", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Exception ex) {
        ((LogInfo) this.logInfoLocal.get()).setExceptionInfo(ex.getMessage());
        ((LogInfo) this.logInfoLocal.get()).setReturnResult((Object) null);
    }


    private void setLogInfo(JoinPoint point, OperationLogRecord operationLogRecord) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        ((LogInfo) this.logInfoLocal.get()).setOperationIp(RequestUtil.getIpAddress(request));
        ((LogInfo) this.logInfoLocal.get()).setUserName(request.getHeader(Constant.TOKENNAME));
        ((LogInfo) this.logInfoLocal.get()).setClassName(point.getSignature().getDeclaringTypeName() + "." + point.getSignature().getName());
        ((LogInfo) this.logInfoLocal.get()).setReqPath(request.getRequestURL().toString());
        ((LogInfo) this.logInfoLocal.get()).setParams(Arrays.toString(point.getArgs()));
        ((LogInfo) this.logInfoLocal.get()).setDate(new Date());
        ((LogInfo) this.logInfoLocal.get()).setSource("Foreground");

        ((LogInfo) this.logInfoLocal.get()).setDescribe(operationLogRecord.describe());
        ((LogInfo) this.logInfoLocal.get()).setModularCode(operationLogRecord.modularCode());
        ((LogInfo) this.logInfoLocal.get()).setOperationLevel(operationLogRecord.operationLevel().toString());
    }
}
